﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;

namespace game
{
    public class AIFighter : Fighter
    {
        

        protected float aimEpsilon = MathHelper.Pi * 0.01f;

        protected float dirToTarget = 0.0f;

        public AIFighter(Scene scene, ModelUnit model, int layerIndex, Vector3 position, Squadron squadron)
            : base(scene, model, layerIndex, position, squadron)
        {
            this.rotation.Y = (float)(ShooterGame.Instance.Random.NextDouble() * 2 * Math.PI - Math.PI);

            ActiveWeaponIndex = RandomHelper.Random.Next(2);
        }

        protected bool leaningLeft = false;
        protected bool leaningRight = false;
        protected bool dodgingLeft = false;
        protected bool dodgingRight = false;

        protected bool isOrder = false;

        protected int msFromOrder = 0;

        protected int orderTime = 500;

        protected const int minTimeToTargetChangeMs = 5000;
        protected int timeFromLastTargetChange = minTimeToTargetChangeMs;

        public override void Update(GameTime gameTime)
        {
            if(isOrder)
            {
                msFromOrder += gameTime.ElapsedGameTime.Milliseconds;
                if (msFromOrder < orderTime)
                {
                    if (leaningLeft)
                        LeanLeft();
                    if (leaningRight)
                        LeanRight();
                    if (dodgingLeft)
                        DodgeLeft();
                    if (dodgingRight)
                        DodgeRight();
                    goto end;
                }
                else
                {
                    leaningLeft = false;
                    leaningRight = false;
                    dodgingLeft = false;
                    dodgingRight = false;
                    isOrder = false;
                }
            }

            Matrix rotY = Matrix.CreateRotationY(rotation.Y);
            Vector3 direction = Vector3.Transform(Vector3.Forward, rotY);
            Ray ray = new Ray(position, direction);

            Vector3 atFront;
            Vector3.Add(ref position, ref direction, out atFront);
            float p1x = position.X, p1z = position.Z,
                  p2x = atFront.X, p2z = atFront.Z;

            foreach (GameObject obj in scene.Layers[LayerIndex])
            {
                if (!(obj is Ship || obj is Asteroid) || obj == this)
                    continue;

                float? intersection = ray.Intersects(obj.GetBSphereTransformed());

                if(intersection != null && intersection < 75000.0f)
                {
                    float px = obj.Position.X, pz = obj.Position.Z;

                    float pointDist = (p2x - p1x) * (pz - p1z) - (p2z - p1z) * (px - p1x);

                    if (pointDist > 0.0f)
                    {
                        dodgingLeft = true;
                        DodgeLeft();
                    }
                    else
                    {
                        dodgingRight = true;
                        DodgeRight();
                    }

                    if (obj is Asteroid)
                        orderTime = 900;
                    else
                    {
                        orderTime = 500;
                        if ((obj as Ship).Army.ID != Army.ID)
                            ShootWeapon();
                    }

                    msFromOrder = 0;
                    isOrder = true;

                    SpeedUp();

                    goto end;
                }   
            }

            timeFromLastTargetChange += gameTime.ElapsedGameTime.Milliseconds;

            if (Target == null || timeFromLastTargetChange > minTimeToTargetChangeMs)
            {
                Target = scene.GetClosestEnemyOnLayer(this);
                if (Target == null)
                {
                    int destLayerIndex = scene.GetClosestLayerWithEnemy(this);
                    if (destLayerIndex != -1)
                    {
                        if (destLayerIndex > LayerIndex)
                            FlyUp();
                        else if (destLayerIndex < LayerIndex)
                            FlyDown();
                    }
                }
                else
                {
                    timeFromLastTargetChange = 0;
                }
            }
            else
            {
                int random1000 = RandomHelper.Random.Next(1000);

                if (random1000 < 5)
                {
                    ShootRocket();
                }

                dirToTarget = (float)Math.Atan2(Target.Position.X - position.X, Target.Position.Z - position.Z);
                dirToTarget -= MathHelper.Pi;
                if (dirToTarget <= -MathHelper.Pi)
                    dirToTarget += MathHelper.TwoPi;
                if (rotation.Y - dirToTarget > aimEpsilon)
                {
                    if (rotation.Y - MathHelper.Pi > dirToTarget)
                    {
                        LeanLeft();
                    }
                    else
                    {
                        LeanRight();
                    }
                    SlowDown();
                }
                else if (rotation.Y - dirToTarget < -aimEpsilon)
                {
                    if (rotation.Y + MathHelper.Pi < dirToTarget)
                    {
                        LeanRight();
                    }
                    else
                    {
                        LeanLeft();
                    }
                    SlowDown();
                }
                else
                {
                    SpeedUp();

                    Vector2 me = new Vector2(position.X, position.Z);
                    Vector2 target = new Vector2(Target.Position.X, Target.Position.Z);
                    float dist;
                    Vector2.Distance(ref me, ref target, out dist);
                    if (dist < 250000 && random1000 < 300)
                    {
                        ShootWeapon();
                    }
                    
                }

                if (!Target.IsAlive || Target.LayerIndex != LayerIndex)
                {
                    Target = null;
                    
                }

                if (Health < 20 && random1000 < 10)
                {
                    Shield.TurnOn();
                }
                
            }

        end:
            base.Update(gameTime);
        }

        public override void DrawOpaque(GameTime gameTime)
        {
            base.DrawOpaque(gameTime);
            //if (Army.ID == 0)
            //{
            //    Text2D.Draw(dirToTarget.ToString(),
            //    new Vector2(200, 0), Color.Red, new Vector2(2, 2));
            //    Text2D.Draw(rotation.Y.ToString(),
            //    new Vector2(400, 0), Color.Red, new Vector2(2, 2));
            //}
        }
    }
}
